<?php
/**
 * Greendizer PHP Library
 * 
 * @category    Greendizer
 * @package     Greendizer_DAL
 * @copyright   Copyright (c) 2009-2010, Greendizer S.A - All rights reserved.
 * @license     Greendizer/Licence.txt
 * @version     1.0
 */

/**
 * @see Greendizer_DAL_Resources
 */
require_once 'Greendizer/DAL/Resource.php';
require_once 'Greendizer/DAL/Exception.php';

/**
 * Represents a collection of resources
 * 
 * @category    Greendizer
 * @package     Greendizer_DAL
 * @copyright   Copyright (c) 2009-2010, Greendizer S.A - All rights reserved.
 * @license     Greendizer/License.txt
 */
abstract class Greendizer_DAL_Collection {
    /**
     * Constant representing the maximum number of resources in one request
     */
    const MAX_LENGTH = 199;

    /**
     * Etag of the collection
     * 
     * @var Greendizer_Net_Etag
     */
    protected $etag;
    
    /**
     * Uri of the collection
     *
     * @var Greendizer_Net_Uri
     */
    protected $uri;
    
    /**
     * Total number of resources 
     *
     * @var integer
     */
    protected $count;
    
    /**
     * Container which initiated the collection
     *
     * @var Greendizer_DAL_Container
     */
    protected $container;
    
    /**
     * Array (Dictionary) of the resources that are part of the collection
     * with resource ID as key and resource object as value
     *
     * @var array
     */
    protected $resources;
    
    /**
     * Array of the resources that are part of the collection
     *
     * @var array 
     */
    protected $resourceAsArray;

    /**
     * Initializes a new instance of Greendizer_DAL_Collection
     *
     * @param Greendizer_DAL_Container $container Container issuing the request
     * @param Greendizer_Net_Uri $uri Location of the collection
     */
    public function __construct(Greendizer_DAL_Container $container, Greendizer_Net_Uri $uri) {
        //Get Args
        $this->container = $container;
        $this->uri = $uri;
        //Head Request to get params
        $this->handleRequest(Greendizer_Net_HttpMethods::HEAD);
    }

    /**
     * Returns the resources of the collection
     *
     * @return array
     */
    public function getResources() {
        return $this->resourceAsArray;
    }

    /**
     * Returns a resource in the collection given its ID
     *
     * @param string $id    Resource ID
     * @return Greendizer_Net_Resource
     * @throws Greendizer_Collections_CollectionException
     */
    public function getResourceById($id) {
        if($this->resources == null){
            throw new Greendizer_DAL_Exception('Collection not populated');
        }
        if(array_key_exists($id, $this->resources)){
            return $this->resources[$id];
        }
        throw new Greendizer_DAL_Exception('Resource ID could not be found in collection');
    }

    /**
     * Returns a resource in the collection give its index in the collection
     *
     * @param integer $index    Index of the resource in the collection
     * @return Greendizer_Net_Resource 
     */
    public function getResourceByIndex($index) {
        return $this->resourceAsArray[$index];
    }
      
    /**
     * Returns the total number of resources in the collection 
     *
     * @return integer  
     */
    public function getCount() {
        return $this->count;
    }

    /**
     * Populates the collection by getting its resources.
     *
     * @param integer $first    Index of the first resource
     * @param interger $count    Number of resources to populate
     */
    public function populate($first=0, $count=self::MAX_LENGTH) {
        $this->handleRequest(Greendizer_Net_HttpMethods::GET);
    }

    /**
     * Handles responses with code 200 Ok or code 206 Partial Response
     *
     * @param string $method
     * @param Greendizer_Net_Response $response 
     */
    protected function handleOkOrPartialResponse($method, Greendizer_Net_Response $response) {
        $this->etag = Greendizer_Net_Etag::parseEtagString($response->getHeader('etag'));

        preg_match('/resources (?P<first>\w+)-(?P<last>\d+)\/(?P<total>\d+)/', $response->getHeader('content-range'), $matches);
        $this->count = isset($matches['total']) ? $matches['total'] : count($this->resourceAsArray);
    }

    /**
     * Handles 204 No Content response 
     *
     * @param Greendizer_Net_Response $response 
     */
    protected function handleNoContentResponse(Greendizer_Net_Response $response) {
        $this->etag = $response->getHeader('etag');
        $this->count = null;
        unset($this->resources);
    }

    /**
     * Handles a NOT MODIFIED $response
     *
     * @param Greendizer_Net_Response $response 
     */
    protected function handleNotModifiedResponse(Greendizer_Net_Response $response) {
        // ......
        throw new Exception('Not implemented yet -  May not be needded');
    }

    /**
     * Handles a request 
     *
     * @param string $method    HTTP Method
     * @param integer $first    Index of first resource
     * @param integer $count    Number of resources requested
     */
    protected function handleRequest($method, $first=0, $count=self::MAX_LENGTH) {

        $credentials = $this->container->getClient()->getCredentials();
        $headers = array(
            'Accept' => 'application/json',
            'Range' => 'resources=' . $first . '-' . ($first + $count),
                //'If-Range' => $this->etag->getEtagString()
        );

        $request = new Greendizer_Net_Request(
                        Greendizer_Net_HttpMethods::GET,
                        $this->uri,
                        $headers,
                        $this->container->getClient()->getAuthType(),
                        $credentials
        );
        $response = $request->getResponse();

        switch ($response->getStatusCode()) {
            case Greendizer_Net_HttpStatusCodes::HTTP_OK:
            case Greendizer_Net_HttpStatusCodes::HTTP_PARTIAL_CONTENT:
                $this->handleOkOrPartialResponse($method, $response);
                break;
            case Greendizer_Net_HttpStatusCodes::HTTP_NO_CONTENT:
                $this->handleNoContentResponse($response);
                break;
            case Greendizer_Net_HttpStatusCodes::HTTP_NOT_MODIFIED:
                $this->handleNotModifiedResponse($response);
                break;
            case Greendizer_Net_HttpStatusCodes::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
                break;
            default:
                throw new Exception($response->getStatusCode() .
                        ': ' . Greendizer_Net_HttpStatusCodes::getStatusMessageForCode($response->getStatusCode()));
        }
    }

}

?>
